﻿#include "flowdata.h"
#include <QDebug>
#include <QThread>
#include <QTableWidgetItem>

FlowData::FlowData(OpcUA_QThread *opcUA, QObject *parent)
    : QObject(parent), m_opcUA(opcUA)
{
    if (m_opcUA)
        qDebug() << u8"FlowData：OPCUA通信对象初始化完成";
    else
        qDebug() << u8"FlowData：OPCUA通信对象未传入（仅调试模式）";

    my_temperatureWriteTimer = new QTimer(this);
    my_temperatureWriteTimer->setInterval(3000); // 设置为3秒间隔

    connect(my_temperatureWriteTimer, &QTimer::timeout, this, &FlowData::on_timeOut_temperatureWrite);

    connect(m_opcUA, &OpcUA_QThread::signals_dataFromHomePageWritten, this, &FlowData::on_writeDataFromHomePage);
}

void FlowData::setTemperature(int16_t temperature1, int16_t temperature2)
{
    m_temperature1 = temperature1;
    m_temperature2 = temperature2;
}

bool FlowData::isValidUInt16(const QString& text, int16_t& outValue)
{
    //空字符串视为-1(未输入的状态）
    if (text.isEmpty())
    {
        outValue = -1;
        return true;
    }

    //禁止包含小数、空格、逗号
    if (text.contains('.') || text.contains(',') || text.contains(' '))
    {
        emit paramRangeError(u8"输入不允许包含小数、空格或逗号");
        return false;
    }

    //转换为整数并检查有效性
    bool isNumber;
    int tempValue = text.toInt(&isNumber);
    if (!isNumber)
    {
        emit paramRangeError(u8"输入不是有效的整数");
        return false;
    }

    //检查范围（0-32767）
    if (tempValue < m_minValue || tempValue > m_maxValue)
    {
        emit paramRangeError(QString(u8"输入必须在%1~%2之间").arg(m_minValue).arg(m_maxValue));
        return false;
    }

    outValue = static_cast<int16_t>(tempValue);
    return true;
}

bool FlowData::isValidLineRunValue(const QString& text, int& outValue)
{
    //空字符串视为-1(未输入的状态）
    if (text.isEmpty())
    {
        outValue = -1;
        return true;
    }

    //禁止包含小数、空格、逗号
    if (text.contains('.') || text.contains(',') || text.contains(' '))
    {
        emit paramRangeError(u8"Line/Run列不允许包含小数、空格或逗号");
        return false;
    }

    //转换为整数并检查有效性
    bool isNumber;
    outValue = text.toInt(&isNumber);
    if (!isNumber)
    {
        emit paramRangeError(u8"Line/Run列输入不是有效的整数");
        return false;
    }

    return true;
}

bool FlowData::validateTableData(int col, const QString& text)
{
    //判断是否为Line/Run列
    bool isLineRunCol = (col == 8 || col == 9 || col == 13 || col == 14 ||
                         col == 18 || col == 19 || col == 22 || col == 23 ||
                         col == 25);

    //Total Time列无需校验（不可编辑）
    if (col == 2)
        return true;

    //校验Line/Run列
    if (isLineRunCol)
    {
        int val;
        return isValidLineRunValue(text, val);
    }
    //校验普通列
    else
    {
        int16_t val;
        return isValidUInt16(text, val);
    }
}

void FlowData::updateTotalTime(QTableWidget* table, int headerRowCount)
{
    QVector<int16_t> durationList = getAllDurationTime(table, headerRowCount);
    // 重新计算所有行的Total Time（基于更新后的durationList）
    for (int i = 0; i < durationList.size(); ++i)
    {
        int tableRow = headerRowCount + i;
        if (tableRow >= table->rowCount())
            continue;

        // 关键修改：重新计算从第0行到当前行的累计时间
        int16_t total = 0;
        for (int j = 0; j <= i; ++j)
        {
            total += durationList[j];
            if (total > m_maxValue)
            {
                total = m_maxValue;
                break; // 超出最大值时截断
            }
        }

        QTableWidgetItem* totalItem = table->item(tableRow, 2);
        if (totalItem)
            totalItem->setText(QString::number(total));
    }
}

void FlowData::updateParamFromTable(QTableWidget* table, int row, int headerRowCount)
{
    if (m_flowParams.isEmpty())
        return;

    int paramIndex = row - headerRowCount;
    if (paramIndex >= 0 && paramIndex < m_flowParams.size())
    {
        //更新当前行参数
        QVector<FlowParam> allParams = m_flowParams;
        //解析后保存
        FlowParam parsed = parseRowToParam(table, row);
        allParams[paramIndex] = parsed;

        //保存所有参数
        clearParams();
        for (const auto& param : allParams)
            addParam(param);
    }
}

int FlowData::saveParamsFromTable(QTableWidget* table, int headerRowCount)
{
    clearParams();
    QVector<int16_t> durationList;

    //收集所有行的Duration Time
    for (int row = headerRowCount; row < table->rowCount(); ++row)
    {
        QTableWidgetItem* stepItem = table->item(row, 0);
        if (!stepItem || stepItem->text().isEmpty())
            continue;

        //解析Duration Time
        int16_t duration = 0;
        QTableWidgetItem* durationItem = table->item(row, 1);
        if (durationItem)
            isValidUInt16(durationItem->text(), duration);

        durationList.append(duration);
    }

    //保存参数并更新Total Time
    int validCount = 0;
    for (int row = headerRowCount; row < table->rowCount(); ++row)
    {
        QTableWidgetItem* stepItem = table->item(row, 0);
        if (!stepItem || stepItem->text().isEmpty())
            continue;

        //计算并更新Total Time
        int16_t total = calculateTotalTime(durationList, validCount);
        QTableWidgetItem* totalItem = table->item(row, 2);
        if (totalItem)
            totalItem->setText(QString::number(total));

        //解析参数并保存
        FlowParam parsed = parseRowToParam(table, row);
        parsed.totalTime = total;
        addParam(parsed);
        validCount++;
    }

    return validCount;
}

bool FlowData::shouldSwitchStep(const QVector<FlowParam>& params, int currentIndex, double elapsedSec)
{
    if (currentIndex >= params.size())
        return true;

    //获取当前步骤信息
    FlowParam currentStep = params[currentIndex];
    double currentStepDuration = currentStep.durationTime;

    //获取上一步的Total Time
    double previousTotalTime = (currentIndex > 0) ? params[currentIndex - 1].totalTime : 0;

    //判断是否达到当前步的结束时间
    return elapsedSec >= (previousTotalTime + currentStepDuration);
}

void FlowData::addParam(const FlowParam& param)
{
    m_flowParams.append(param);
}

void FlowData::clearParams()
{
    m_flowParams.clear();
}

QVector<FlowParam> FlowData::getParams() const
{
    return m_flowParams;
}

int16_t FlowData::calculateTotalTime(const QVector<int16_t>& durationList, int index)
{
    if (index < 0 || index >= durationList.size())
        return 0;

    int16_t total = 0;
    for (int i = 0; i <= index; ++i)
    {
        total += durationList[i];
        //超出最大值时截断
        if (total > m_maxValue)
        {
            total = m_maxValue;
            emit paramRangeError(u8"Total Time超出最大值32767，已自动截断");
            break;
        }
    }

    return total;
}

void FlowData::writeStepToKepserver(const FlowParam& param)
{
    //检查OPCUA对象和写入状态
    if (!m_opcUA || m_isWriting)
    {
        emit writeSuccess(u8"写入跳过：OPCUA对象未就绪或正在写入");
        return;
    }
    m_isWriting = true;

    // 复制参数并处理-1值（使用上一次有效参数）
    FlowParam currentParam = param;

    // 处理int16_t类型参数
    if (currentParam.step == -1) currentParam.step = m_prevParam.step;
    if (currentParam.durationTime == -1) currentParam.durationTime = m_prevParam.durationTime;
    if (currentParam.totalTime == -1) currentParam.totalTime = m_prevParam.totalTime;
    if (currentParam.setTemp1 == -1) currentParam.setTemp1 = m_prevParam.setTemp1;
    if (currentParam.setTemp2 == -1) currentParam.setTemp2 = m_prevParam.setTemp2;
    if (currentParam.setPressure == -1) currentParam.setPressure = m_prevParam.setPressure;

    if (currentParam.mo1Source == -1) currentParam.mo1Source = m_prevParam.mo1Source;
    if (currentParam.mo1Push == -1) currentParam.mo1Push = m_prevParam.mo1Push;
    if (currentParam.mo1Press == -1) currentParam.mo1Press = m_prevParam.mo1Press;

    if (currentParam.mo2Source == -1) currentParam.mo2Source = m_prevParam.mo2Source;
    if (currentParam.mo2Push == -1) currentParam.mo2Push = m_prevParam.mo2Push;
    if (currentParam.mo2Press == -1) currentParam.mo2Press = m_prevParam.mo2Press;

    if (currentParam.o1Source == -1) currentParam.o1Source = m_prevParam.o1Source;
    if (currentParam.o1Push == -1) currentParam.o1Push = m_prevParam.o1Push;

    if (currentParam.o2Source == -1) currentParam.o2Source = m_prevParam.o2Source;
    if (currentParam.o2Push == -1) currentParam.o2Push = m_prevParam.o2Push;

    if (currentParam.N2Source == -1) currentParam.N2Source = m_prevParam.N2Source;

    // 处理bool类型参数：根据isEmpty标记判断是否复用旧值
    if (param.mo1LineIsEmpty) currentParam.mo1Line = m_prevParam.mo1Line;
    if (param.mo1RunIsEmpty) currentParam.mo1Run = m_prevParam.mo1Run;

    if (param.mo2LineIsEmpty) currentParam.mo2Line = m_prevParam.mo2Line;
    if (param.mo2RunIsEmpty) currentParam.mo2Run = m_prevParam.mo2Run;

    if (param.o1LineIsEmpty) currentParam.o1Line = m_prevParam.o1Line;
    if (param.o1RunIsEmpty) currentParam.o1Run = m_prevParam.o1Run;

    if (param.o2LineIsEmpty) currentParam.o2Line = m_prevParam.o2Line;
    if (param.o2RunIsEmpty) currentParam.o2Run = m_prevParam.o2Run;

    if (param.N2ValveIsEmpty) currentParam.N2Valve = m_prevParam.N2Valve;

    //保存上一次的有效参数
    m_prevParam = currentParam;

    //记录当前步骤的开始时间
    m_stepStartTime = QDateTime::currentMSecsSinceEpoch();

    qDebug() << u8"调用写入函数了，到Mo2值："
             << currentParam.step
             << currentParam.durationTime
             << currentParam.totalTime
             << currentParam.setTemp1
             << currentParam.setTemp2
             << currentParam.setPressure
             << currentParam.mo1Source
             << currentParam.mo1Push
             << currentParam.mo1Line
             << currentParam.mo1Run
             << currentParam.mo1Press
             << currentParam.mo2Source
             << currentParam.mo2Push
             << currentParam.mo2Line
             << currentParam.mo2Run
             << currentParam.mo2Press;

    qDebug() << u8"调用写入函数了，到N2值："
             << currentParam.o1Source
             << currentParam.o1Push
             << currentParam.o1Line
             << currentParam.o1Run
             << currentParam.o2Source
             << currentParam.o2Push
             << currentParam.o2Line
             << currentParam.o2Run
             << currentParam.N2Source
             << currentParam.N2Valve;

    //将数据转换成写入Plc的值
    FlowParam tempParam = convertParam(currentParam);

    QVector<int16_t> flowValues;
    QVector<int16_t> pressureValues;
    QVector<bool> valves;

    flowValues.append(tempParam.N2Source);
    flowValues.append(tempParam.o1Push);
    flowValues.append(tempParam.o1Source);
    flowValues.append(tempParam.o2Push);
    flowValues.append(tempParam.o2Source);
    flowValues.append(tempParam.mo1Push);
    flowValues.append(tempParam.mo1Source);
    flowValues.append(tempParam.mo2Source);
    flowValues.append(tempParam.mo2Push);

    pressureValues.append(tempParam.mo1Press);
    pressureValues.append(tempParam.mo2Press);

    valves.append(tempParam.N2Valve);
    valves.append(tempParam.o1Line);
    valves.append(tempParam.o1Run);
    valves.append(tempParam.o2Line);
    valves.append(tempParam.o2Run);
    valves.append(tempParam.mo1Line);
    valves.append(tempParam.mo1Run);
    valves.append(tempParam.mo2Line);
    valves.append(tempParam.mo2Run);

    m_opcUA->writeDataFromHomePage(flowValues, pressureValues, valves);

    m_isWriting = false;
    emit writeSuccess(QString(u8"第%1步参数已发送写入指令").arg(param.step));
}

void FlowData::stopWrite()
{
    m_isWriting = false;
    if (m_opcUA)
    {
        //调用OPCUA停止接口（如需要）
        //m_opcUA->abortWrite();
        //
        //
        //
        //
    }
    emit writeSuccess(u8"写入已停止");
}

void FlowData::setActiveStatus(bool status)
{
    m_flowChartIsActive = status;
    if (status) {
        if (!my_temperatureWriteTimer->isActive()) {
            my_temperatureWriteTimer->start();
            emit writeSuccess(u8"FlowData:温度定时写入已启动");
        }
    } else {
        if (my_temperatureWriteTimer->isActive()) {
            my_temperatureWriteTimer->stop();
            m_opcUA->writeTemperature(true, false,  0, 0); //结束前给温控表设定停止升温命令false,温度设定为0
            QVector<bool > valve;
            valve.append(0);
            valve.append(0);
            valve.append(0);
            valve.append(0);
            valve.append(0);
            valve.append(0);
            valve.append(0);
            valve.append(0);
            valve.append(0);
            valve.append(0);
            m_opcUA->writeAllValveStatus(valve);
            emit writeSuccess(u8"FlowData:温度定时写入已停止");
        }
    }
}

void FlowData::on_timeOut_temperatureWrite()
{
    // 检查是否处于活跃状态
    if (!m_flowChartIsActive) {
        my_temperatureWriteTimer->stop();
        return;
    }

    // 检查当前温度是否已达到设定温度，若达到则跳过写入
    if (m_temperature1 == m_prevParam.setTemp1 && m_temperature2 == m_prevParam.setTemp2) {
        qDebug() << u8"温度已达到设定值，跳过本次写入";
        return;
    }

    // 计算每3秒的温度增量
    int16_t temp1Increment = calculateTemperatureIncrement(
        m_prevParam.setTemp1, m_temperature1, m_prevParam.durationTime);
    int16_t temp2Increment = calculateTemperatureIncrement(
        m_prevParam.setTemp2, m_temperature2, m_prevParam.durationTime);

    // 计算新的设定温度
    int16_t newTemp1 = m_temperature1 + temp1Increment;
    int16_t newTemp2 = m_temperature2 + temp2Increment;

    if(newTemp1 > m_prevParam.setTemp1)
        newTemp1 = m_prevParam.setTemp1;
    if(newTemp2 > m_prevParam.setTemp2)
        newTemp2 = m_prevParam.setTemp2;

    // 确保新温度在有效范围内
    newTemp1 = qBound(m_minValue, newTemp1, m_maxValue);
    newTemp2 = qBound(m_minValue, newTemp2, m_maxValue);

    // 写入新的温度值到OPCUA服务器
    if (m_opcUA) {
        m_opcUA->writeTemperature(0, 1,  newTemp1, newTemp2);
        qDebug() << QString(u8"温度已更新: T1=%1, T2=%2").arg(newTemp1).arg(newTemp2);
    }
}

void FlowData::on_writeDataFromHomePage(bool success)
{
    emit writeSuccess(QString(u8"写入参数结果：%1").arg(success));
}

//解析整数参数并赋值
void FlowData::parseInt16Param(QTableWidget* table, int row, int col, int16_t& param)
{
    QTableWidgetItem* item = table->item(row, col);
    if (item)
    {
        int16_t value = 0;
        isValidUInt16(item->text(), value);
        param = value;
    }
}

//解析Line/Run参数并转换为布尔值,增加isEmpty标记的引用，用于记录空值状态
void FlowData::parseBoolParam(QTableWidget* table, int row, int col, bool& param, bool& isEmpty)
{
    isEmpty = true;  // 默认标记为空值
    QTableWidgetItem* item = table->item(row, col);
    if (item)
    {
        int value = 0;
        bool valid = isValidLineRunValue(item->text(), value);
        if (valid)
        {
            if (value == -1)
            {
                //单元格为空，保持param默认值，isEmpty保持true
                return;
            }
            else
            {
                //有效输入，更新param值，标记isEmpty为false
                param = (value != 0);  // 非0值视为true
                isEmpty = false;
            }
        }
    }
}

//解析整行数据为FlowParam结构体
FlowParam FlowData::parseRowToParam(QTableWidget* table, int row)
{
    FlowParam param;

    // 基础参数列
    parseInt16Param(table, row, 0, param.step);
    parseInt16Param(table, row, 1, param.durationTime);
    parseInt16Param(table, row, 2, param.totalTime);
    parseInt16Param(table, row, 3, param.setTemp1);
    parseInt16Param(table, row, 4, param.setTemp2);
    parseInt16Param(table, row, 5, param.setPressure);

    // Mo1组（6-10列）
    parseInt16Param(table, row, 6, param.mo1Source);
    parseInt16Param(table, row, 7, param.mo1Push);
    parseBoolParam(table, row, 8, param.mo1Line, param.mo1LineIsEmpty);
    parseBoolParam(table, row, 9, param.mo1Run, param.mo1RunIsEmpty);
    parseInt16Param(table, row, 10, param.mo1Press);

    // Mo2组（11-15列）
    parseInt16Param(table, row, 11, param.mo2Source);
    parseInt16Param(table, row, 12, param.mo2Push);
    parseBoolParam(table, row, 13, param.mo2Line, param.mo2LineIsEmpty);
    parseBoolParam(table, row, 14, param.mo2Run, param.mo2RunIsEmpty);
    parseInt16Param(table, row, 15, param.mo2Press);

    // O-1组（16-19列）
    parseInt16Param(table, row, 16, param.o1Source);
    parseInt16Param(table, row, 17, param.o1Push);
    parseBoolParam(table, row, 18, param.o1Line, param.o1LineIsEmpty);
    parseBoolParam(table, row, 19, param.o1Run, param.o1RunIsEmpty);

    // O-2组（20-23列）
    parseInt16Param(table, row, 20, param.o2Source);
    parseInt16Param(table, row, 21, param.o2Push);
    parseBoolParam(table, row, 22, param.o2Line, param.o2LineIsEmpty);
    parseBoolParam(table, row, 23, param.o2Run, param.o2RunIsEmpty);

    // O-3组（24-25列）
    parseInt16Param(table, row, 24, param.N2Source);
    parseBoolParam(table, row, 25, param.N2Valve, param.N2ValveIsEmpty);

    return param;
}


QVector<int16_t> FlowData::getAllDurationTime(QTableWidget* table, int headerRowCount)
{
    QVector<int16_t> durationList;
    //按表格实际数据行，顺序读取，不含表头
    for (int row = headerRowCount; row < table->rowCount(); ++row)
    {
        //只处理有Step值的有效行
        QTableWidgetItem* stepItem = table->item(row, 0);
        if (!stepItem || stepItem->text().isEmpty())
        {
            durationList.append(0);
            continue;
        }

        //解析Duration Time（空值视为0）
        QTableWidgetItem* durationItem = table->item(row, 1);
        int16_t duration = 0;
        if (durationItem && !durationItem->text().isEmpty())
            isValidUInt16(durationItem->text(), duration);

        durationList.append(duration);
    }
    return durationList;
}

FlowParam FlowData::convertParam(const FlowParam& original)
{
    FlowParam converted = original;

    //Mo1组
    converted.mo1Source = PLCDataConversion::convert_100to24576(original.mo1Source);
    converted.mo1Push = PLCDataConversion::convert_1000to24576(original.mo1Push);
    converted.mo1Press = PLCDataConversion::convert_300to24576(original.mo1Press);

    //Mo2组
    converted.mo2Source = PLCDataConversion::convert_300to24576(original.mo2Source);
    converted.mo2Push = PLCDataConversion::convert_1000to24576(original.mo2Push);
    converted.mo2Press = PLCDataConversion::convert_300to24576(original.mo2Press);

    //O-1组
    converted.o1Source = PLCDataConversion::convert_300to24576(original.o1Source);
    converted.o1Push = PLCDataConversion::convert_1000to24576(original.o1Push);

    //O-2组
    converted.o2Source = PLCDataConversion::convert_30to24576(original.o2Source);
    converted.o2Push = PLCDataConversion::convert_1000to24576(original.o2Push);

    //N2组
    converted.N2Source = PLCDataConversion::convert_3000to24576(original.N2Source);

    //其他值：不转化，用原值

    return converted;
}

int16_t FlowData::calculateTemperatureIncrement(int16_t targetTemp, int16_t currentTemp, int16_t duration)
{
    //避免除以零错误
    if (duration <= 0) {
        return 0;
    }

    //计算当前步骤已运行时间（秒）
    qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
    double elapsedSec = (currentTime - m_stepStartTime) / 1000.0;

    //剩余时间 = 总时长 - 已运行时间（确保不小于1秒，避免除以零）
    double remainingTime = qMax(1.0, duration - elapsedSec);

    //计算剩余时间内需要的温度增量
    int16_t delta = targetTemp - currentTemp;
    //目标温度低于当前温度时不加速升温
    if (delta <= 0) {
        return static_cast<int16_t>(delta / remainingTime * 3);
    }

    // 定义三个阶段的时间比例和对应的升温速率（每3秒）
    const double fastRatio = 0.8;    //前30%时间
    const double mediumRatio = 0.15;  //中间40%时间
    const int16_t fastIncrement = 20;  //快速阶段每3秒升温4度
    const int16_t mediumIncrement = 12; //中间阶段每3秒升温2度

    double fastTimeThreshold = duration * fastRatio;
    double mediumTimeThreshold = duration * (fastRatio + mediumRatio);

    double increment;
    if (elapsedSec < fastTimeThreshold) {
        //快速升温阶段：固定每3秒4度
        increment = fastIncrement;
    } else if (elapsedSec < mediumTimeThreshold) {
        //中间升温阶段：固定每3秒2度
        increment = mediumIncrement;
    } else {
        //正常升温阶段：按剩余时间均匀计算
        increment = delta / remainingTime * 3;
    }

    //确保升温量不会超过所需总增量（避免超过目标温度）
    increment = qMin(increment, static_cast<double>(delta));
    //确保温度增量在有效范围内
    if (increment > INT16_MAX) {
        return INT16_MAX;
    } else if (increment < INT16_MIN) {
        return INT16_MIN;
    }

    return static_cast<int16_t>(increment);
}
